# -*- encoding: utf-8 -*-
# @Author：lijinxi
# @Time ：2020/12/1 13:20
# @File：socket_client.py

import logging
import logging.config
import socket
import os
import threading
from tqdm import tqdm


class SocketClient:
    def __init__(self, log_queue, host='localhost', port=9999, username='ftpuser', password='1234'):
        self.host = host
        self.port = port
        self.username = username
        self.password = password

        logging.config.fileConfig('../config/logging.cfg')  # 配置日志
        self.log_queue = log_queue  # 日志队列

        self.cmd_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 命令端口
        self.upload_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.download_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    def connect_valid(self):  # 校验用户是否在数据库
        self.cmd_sock.connect((self.host, self.port))
        data = {
            'username': self.username,
            'password': self.password,
        }
        self.cmd_sock.send(str(data).encode('utf-8'))  # 发送用户信息
        msg, status_code = self.cmd_sock.recv(1024).decode('utf-8').split(':')  # 返回数据信息
        self.log_queue.put(msg)
        if status_code != 'OK':
            self.cmd_sock.close()
        return status_code

    def upload(self, local_path, remote_path):
        logging.info(f"上传的文件在本地: {local_path}, 保存在: {remote_path}.")
        self.log_queue.put(f"上传的文件在本地: {local_path}, 保存在: {remote_path}.")

        upload_thread = threading.Thread(target=self.handle_upload, args=(local_path, remote_path), daemon=True)
        upload_thread.start()

    def handle_upload(self, local_path, remote_path):  # 文件上传新进程, 防止阻塞
        self.upload_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        datalist = []
        with open(local_path, 'rb') as f:
            while True:
                _data = f.read(1024)
                if not _data:
                    break
                datalist.append(_data)
        size = os.stat(local_path).st_size  # 文件大小
        bar = tqdm(total=size, initial=0, unit='B', unit_scale=True, desc=os.path.basename(local_path))
        summary = {
            'len': len(datalist),
            'size': size,
        }
        cmd_data = {
            'upload': remote_path,
            'summary': summary
        }
        self.cmd_sock.send(str(cmd_data).encode('utf-8'))  # 发送命令

        self.upload_sock.connect((self.host, self.port + 100))
        _dec = len(datalist) // 20  # 为了使效果更好
        count = 0
        for _data in datalist:
            count += 1
            self.upload_sock.send(_data)
            if count % _dec == 0:
                bar.update(1024 * _dec)
                self.log_queue.put("Uploading...\t" + str(bar))
        self.log_queue.put(os.path.basename(local_path) + ',文件上传完成.')
        bar.close()
        self.upload_sock.close()

    def download(self, local_path, remote_path):
        logging.info(f"下载的文件在远程: {remote_path}, 保存在: {local_path}.")
        self.log_queue.put(f"下载的文件在远程: {remote_path}, 保存在: {local_path}.")
        download_thread = threading.Thread(target=self.handle_download, args=(local_path, remote_path), daemon=True)
        download_thread.start()

    def handle_download(self, local_path, remote_path):
        self.download_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        cmd_data = {
            'download': remote_path,
        }
        self.cmd_sock.send(str(cmd_data).encode('utf-8'))  # 发送指令
        summary = eval(self.cmd_sock.recv(1024).decode('utf-8'))
        # cmd_data = {  # 摆设
        #  'recv_summary_download': ''
        # }
        # self.cmd_sock.send(str(cmd_data).encode('utf-8'))  # 发送指令

        self.download_sock.connect((self.host, self.port + 200))
        bar = tqdm(total=summary['size'], initial=0, unit='B', unit_scale=True, desc=os.path.basename(local_path))
        _dec = summary['len'] // 20  # 为了使效果更好
        with open(local_path, 'wb') as f:
            for i in range(summary['len']):
                f.write(self.download_sock.recv(1024))
                if i % _dec == 0:
                    bar.update(_dec * 1024)
                    self.log_queue.put("Downloading...\t" + str(bar))
        self.download_sock.close()
        self.log_queue.put(os.path.basename(local_path) + ',文件下载完成.')
        bar.close()

    def ls_remote_dir(self, path):
        if self.cmd_sock is not None:
            data = {
                'ls_remote_dir': path
            }

            self.cmd_sock.send(str(data).encode('utf-8'))
            recv_data = eval(self.cmd_sock.recv(1024).decode('utf-8'))
            abs_path, folders, files, sizes = recv_data.values()
            return abs_path, folders, files, sizes


if __name__ == '__main__':
    sc = SocketClient()
